package utils

import (
	"bytes"
	"crypto/tls"
	"errors"
	"fmt"
	"github.com/mojocn/base64Captcha"
	"image/color"
	"io/ioutil"
	"math/rand"
	"net/http"
	"os"
	"runtime/debug"
	"strconv"
	"strings"
	"time"

	"github.com/bwmarrin/snowflake"
	log "github.com/sirupsen/logrus"
)

func HandlePanic() {
	if r := recover(); r != nil {
		log.Errorf("panic %v \n%s", r, debug.Stack())
	}
}

func snowflakeInit(startTime string, machineID int64) (node *snowflake.Node) {
	var st time.Time
	st, err := time.Parse("2006-01-02", startTime)
	if err != nil {
		return nil
	}
	snowflake.Epoch = st.UnixNano() / 1e6
	node, err = snowflake.NewNode(machineID)
	if err != nil {
		log.WithField("Func", "utils.snowflakeInit").Warnf("snowflakeInit id error, error:%v", err)
		return nil
	}
	return node
}

func IdGenerate() int64 {
	currtime := time.Now().Format("2006-01-02")
	node := snowflakeInit(currtime, 1)
	return node.Generate().Int64()
}

// 字符串数组转int拼接字符串
func StrArray2String(array []string) string {
	res := ""
	leng := len(array)
	if leng <= 0 {
		return res
	}
	for _, v := range array {
		va, _ := strconv.Atoi(v)
		res = fmt.Sprintf("%s,%d", res, va)
	}
	res = res[1:]
	return res
}

// 字符串数组转int拼接字符串
func IntArray2String(array []int) string {
	res := ""
	leng := len(array)
	if leng <= 0 {
		return res
	}
	for _, v := range array {
		res = fmt.Sprintf("%s,%d", res, v)
	}
	res = res[1:]
	return res
}

// 判断文件夹是否存在
func PathExists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return false, err
}

// 将int类型slice 转为 map[int]struct{}。
func ConvertIntSlice2Map(sl []int) map[int]struct{} {
	set := make(map[int]struct{}, len(sl))
	for _, v := range sl {
		set[v] = struct{}{}
	}
	return set
}

const STRING_FORMAT_TIME string = "2006-01-02 15:04:05"
const STRING_FORMAT_TIME_YYYYMMDDHHMMSS string = "20060102150405"

// 获取当前时间，自定义格式
func GetCurTime(f string) string {
	return FormatAsString(time.Now(), f)
}

// 获取当前时间。字符串格式："2006-01-02 15:04:05"
func GetCurrentTime() string {
	return FormatAsString(time.Now(), "")
}

// 获取某一天的0点（字符串格式）
func GetZeroTime(d time.Time) string {
	time := GetZeroTimeD(d)
	return FormatAsString(time, "")
}

// 获取某一天的0点(时间格式)
func GetZeroTimeD(d time.Time) time.Time {
	return time.Date(d.Year(), d.Month(), d.Day(), 0, 0, 0, 0, d.Location())
}

// 获取某一天的23:59:59
func Get24pm(d time.Time) string {
	time := time.Date(d.Year(), d.Month(), d.Day(), 23, 59, 59, 0, d.Location())
	return FormatAsString(time, "")
}

// 字符串格式转换为时间格式
func FormatAsTime(timeStr string) time.Time {
	local, _ := time.LoadLocation("Asia/Shanghai")
	timeDate, _ := time.ParseInLocation(STRING_FORMAT_TIME, timeStr, local)
	return timeDate
}

// 时间格式转换为字符串格式
func FormatAsString(t time.Time, f string) string {
	fo := STRING_FORMAT_TIME
	if f == "" {
		f = fo
	}
	return t.Format(f)
}

// 生成6位随机数
func Get6bitRandomDigit() string {
	rnd := rand.New(rand.NewSource(time.Now().UnixNano()))
	return fmt.Sprintf("%06v", rnd.Int31n(900000)+100000)
}

// 生成4位随机数
func Get4bitRandomDigit() string {
	rnd := rand.New(rand.NewSource(time.Now().UnixNano()))
	return fmt.Sprintf("%04v", rnd.Int31n(10000))
}

func HttpRequest(url, mime string, data []byte) ([]byte, error) {
	req, err := http.NewRequest("POST", url, bytes.NewBuffer(data))
	if err != nil {
		return nil, err
	}
	if mime == "" {
		mime = "application/json"
	}
	req.Header.Set("Content-Type", mime)
	client := http.Client{
		Timeout: time.Duration(30 * time.Second),
	}
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	} else if resp.StatusCode != http.StatusOK {
		errMsg := fmt.Sprintf("http request failure. url = %s the respcode is:%d", url, resp.StatusCode)
		return nil, errors.New(errMsg)
	}
	defer resp.Body.Close()
	msg, _ := ioutil.ReadAll(resp.Body)
	return msg, nil
}
func HttpPostFormReq(url, mime, data string) ([]byte, error) {
	req, err := http.NewRequest("POST", url, strings.NewReader(data))
	if err != nil {
		return nil, err
	}
	req.Header.Add("Content-Type", mime)
	client := &http.Client{ // 忽略证书验证
		Transport: &http.Transport{
			TLSClientConfig: &tls.Config{
				InsecureSkipVerify: true,
			},
		},
		Timeout: time.Duration(5 * time.Second),
	}
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	} else if resp.StatusCode != http.StatusOK {
		errMsg := fmt.Sprintf("http request failure. url = %s the respcode is:%d", url, resp.StatusCode)
		return nil, errors.New(errMsg)
	}
	defer resp.Body.Close()
	msg, _ := ioutil.ReadAll(resp.Body)
	return msg, nil
}

// 设置自带的store
var store = base64Captcha.DefaultMemStore

// 生成验证码
func CaptMake() (id, b64s string, err error) {
	var driver base64Captcha.Driver
	var driverString base64Captcha.DriverString
	// 配置验证码信息
	captchaConfig := base64Captcha.DriverString{
		Height:          60,
		Width:           200,
		NoiseCount:      0,
		ShowLineOptions: 2 | 4,
		Length:          4,
		Source:          "1234567890qwertyuioplkjhgfdsazxcvbnm",
		BgColor: &color.RGBA{
			R: 202,
			G: 234,
			B: 206,
			A: 254,
		},
		Fonts: []string{"wqy-microhei.ttc"},
	}

	driverString = captchaConfig
	driver = driverString.ConvertFonts()
	captcha := base64Captcha.NewCaptcha(driver, store)
	id, base64, err := captcha.Generate()
	return id, base64, err
}

// 验证captcha是否正确
func CaptVerify(id string, capt string) bool {
	if store.Verify(id, capt, false) {
		return true
	} else {
		return false
	}
}
